import pandas as pd
import numpy as np
class BaselineCFBySGD(object):
    def __init__(self,number_epochs,alpha,reg,columns=["uid","iid","rating"]):
#         #梯度下降最高的迭代次数
        self.number_epochs=number_epochs
#       学习率
        self.alpha=alpha
#       正则参数
        self.reg=reg
#       数据集中  user   item  rating 字段
        self.columns=columns
    def fit(self,dataset):
        '''
        :param dataset: uid,iid,rating
        :return:
        '''
        self.dataset=dataset
#         用户评分数据
        self.users_ratings=dataset.groupby(self.columns[0]).agg([list])[[self.columns[1],self.columns[2]]]
#         物品评分数据
        self.items_ratings=dataset.groupby(self.columns[1]).agg([list])[[self.columns[0],self.columns[2]]]
#         全局评分
        self.global_mean=self.dataset[self.columns[2]].mean()
#         调用sgd方法训练模型参数
        self.bu,self.bi=self.sgd()
    def sgd(self):
        '''
        利用随机梯度下降，优化bu,bi的值
        :return: bu,bi
        '''
        bu=dict(zip(self.users_ratings.index,np.zeros(len(self.users_ratings))))
        bi=dict(zip(self.items_ratings.index,np.zeros(len(self.items_ratings))))
        for i in range(self.number_epochs):
            print("正在迭代：iter{:}".format(i))
            for uid,iid,real_rating in self.dataset.itertuples(index=False):
                error=real_rating-(self.global_mean+bu[uid]+bi[iid])
                bu[uid]+=self.alpha*(error-self.reg*bu[uid])
                bi[iid]+=self.alpha*(error-self.reg*bi[iid])
        return bu,bi
    def predict(self,uid,iid):
        predict_rating=self.global_mean+self.bu[uid]+self.bi[iid]
        return predict_rating
if __name__ == '__main__':
    dtype=[("userId",np.int32),("movieId",np.int32),("rating",np.float32)]
    dataset=pd.read_csv("ratings.csv",usecols=range(3),dtype=dict(dtype))
    bcf=BaselineCFBySGD(15,0.1,0.5,["userId","movieId","rating"])
    bcf.fit(dataset)
    while True:
        uid=int(input("uid:"))
        iid=int(input("iid:"))
        print(bcf.predict(uid,iid))

